﻿using System;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;

namespace BrasilFramework.Controle.Silverlight.Conversores
{
    internal class Objeto
    {
        /// <summary>
        /// Ler o valor de uma propriedade de um objeto
        /// </summary>
        /// <param name="objeto">Objeto</param>
        /// <param name="propriedade">Nome da propriedade</param>
        /// <returns>Valor da propriedade</returns>
        public static PropertyInfo LerPropriedade(object objeto, string propriedade)
        {
            if (objeto == null)
                return null;

            int idx = propriedade.IndexOf('.');
            return idx > 0 ?
                LerPropriedade(objeto.GetType().GetProperty(propriedade.Remove(idx)).GetValue(objeto, null), propriedade.Substring(idx + 1))
                : objeto.GetType().GetProperty(propriedade);
        } 

        /// <summary>
        /// Ler o valor de uma propriedade de um objeto
        /// </summary>
        /// <param name="objeto">Objeto</param>
        /// <param name="propriedade">Nome da propriedade</param>
        /// <returns>Valor da propriedade</returns>
        public static object LerValor(object objeto, string propriedade)
        {
            if (objeto == null)
                return null;

            int idx = propriedade.IndexOf('.');
            return idx > 0 ?
                LerValor(objeto.GetType().GetProperty(propriedade.Remove(idx)).GetValue(objeto, null), propriedade.Substring(idx + 1))
                : objeto.GetType().GetProperty(propriedade).GetValue(objeto, null);
        } 
    }
    /// <summary>
    /// Retorna o primeiro valor diferente de Nulo dentro da lista informada como parâmetro.
    /// </summary>
    public class CoalesceConverter : IValueConverter
    {
        #region IValueConverter Members

        /// <summary>
        /// Retorna o primeiro valor diferente de Nulo dentro da lista informada como parâmetro.
        /// </summary>
        /// <param name="value">Objeto raiz.</param>
        /// <param name="targetType"></param>
        /// <param name="parameter">Expressão. Ex.: Cliente.Empresa.Nome:Cliente.Pessoa.Nome. O primeiro valor não nulo deverá ser retornado.</param>
        /// <param name="culture"></param>
        /// <returns>Primeiro valor diferente de nulo.</returns>
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (parameter == null)
                throw new ArgumentNullException("parameter");

            var lista = parameter.ToString().Split(':');

            return lista.Select(enderecoObjeto => Objeto.LerValor(value, enderecoObjeto)).FirstOrDefault(valor => valor != null);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    /// <summary>
    /// Converte o Objeto em Texto no seguinte formato: "Separador :{NomePropriedadeA, NomePropriedadeB}"
    /// </summary>
    public class ConversorObjetoTexto : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value == null) return value;

            try
            {
                string parametro = parameter.ToString();

                //[0] - Separador entre as propriedades. Ex.: PropriedadeA + Separador + Propriedade2.
                string[] listaParametro = parametro.Split(':');
                string separador = listaParametro[0];
                string[] propriedades = listaParametro[1].Trim().Split(',');

                return propriedades.Select(t =>
                                               {
                                                   object valor = Objeto.LerValor(value, t.Trim());
                                                   if (valor != null && valor.GetType() == typeof(DateTime))
                                                       return ((DateTime)valor).ToString("dd/MM/yyyy");

                                                   return valor;
                                               })
                    .Where(valor => valor != null)
                    .Aggregate(string.Empty, (current, valor) => current + (valor + separador))
                    .TrimEnd(separador.ToCharArray());
            }
            catch (Exception)
            {
                throw new FormatException("Parâmetros inválidos. Ex.: Separador :{NomePropriedadeA, NomePropriedadeB} ");
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion

    }

    /// <summary>
    /// Converts the given color to a SolidColorBrush
    /// </summary>
    public class ColorToSolidColorBrushConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var c = (Color)value;

            return new SolidColorBrush(c);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    /// <summary>   
    /// A type converter for converting image offset into render transform  
    /// </summary>   
    public class ImageOffsetConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var dblVal = (double)value;
            var tt = new TranslateTransform { Y = dblVal };
            return tt;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    /// <summary>
    /// Converts radius to diameter
    /// </summary>
    public class RadiusToDiameterConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var dblVal = (double)value;

            return (dblVal * 2);
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    /// <summary>
    /// Calculates the pointer position
    /// </summary>
    public class PointerCenterConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var dblVal = (double)value;
            var tg = new TransformGroup();
            var rt = new RotateTransform();
            var tt = new TranslateTransform { X = dblVal / 2 };

            tg.Children.Add(rt);
            tg.Children.Add(tt);

            return tg;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    /// <summary>
    /// Calculates the range indicator light position
    /// </summary>
    public class RangeIndicatorLightPositionConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var dblVal = (double)value;
            var tg = new TransformGroup();
            var rt = new RotateTransform();
            var tt = new TranslateTransform { Y = dblVal };

            tg.Children.Add(rt);
            tg.Children.Add(tt);

            return tg;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    /// <summary>
    /// Converts the given Size to height and width
    /// </summary>
    public class SizeConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            double i = 0;
            var s = (Size)value;
            if (parameter.ToString() == "Height")
            {
                i = s.Height;
            }
            else if (parameter.ToString() == "Width")
            {
                i = s.Width;
            }

            return i;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    /// <summary>
    /// Scaling factor for drawing the glass effect.
    /// </summary>
    public class GlassEffectWidthConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var dbl = (double)value;
            return (dbl * 2) * 0.94;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

    /// <summary>
    /// Converts background color to Gradient effect
    /// </summary>
    public class BackgroundColorConverter : IValueConverter
    {
        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var c = (Color)value;
            var radBrush = new RadialGradientBrush();
            var g1 = new GradientStop { Offset = 0.982, Color = c };
            var g2 = new GradientStop { Color = Color.FromArgb(0xFF, 0xAF, 0xB2, 0xB0) };
            radBrush.GradientStops.Add(g1);
            radBrush.GradientStops.Add(g2);
            return radBrush;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }
}